'''
Created on 2010/07/06

@author: yukiyonezawa
'''
from pyrfid.DataProtocol.DSFID.AccessMethod.AccessMethod import AccessMethod
from pyrfid.DataProtocol.LogicalMemory.DataSet import DataSet
from pyrfid.DataProtocol.DSFID.Processor.Compactor import Compactor

import sys


from pyrfid.DataProtocol.DSFID.DataFormat.RootOIDEncoded import RootOIDEncoded
from pyrfid.DataProtocol.LogicalMemory.LogicalMemory import LogicalMemory
from pyrfid.DataProtocol.CommandResponseUnit.ReadObjectsCRU import ReadObjectsCRU
from pyrfid.Util.Util import Util
from pyrfid.DataProtocol.DSFID.DataFormat.DataFormatUtil import DataFormatUtil
from pyrfid.DataProtocol.DSFID.DataFormat.FullFeatured import FullFeatured
from pyrfid.DataProtocol.AddObject import AddObject
from pyrfid.ApplicationInterface.argument.WriteResponses import WriteResponses

class NonDirectory(AccessMethod):
    '''
    classdocs
    '''
    ACCESS_METHOD_ID = 0; 
    driver = object()
    logical_memory = object()
    
    ALLOW_COMPACTION_TYPE = [AddObject.APPLICATION_DEFINED, AddObject.COMPACT, AddObject.UTF8_DATA]
    
    
    def __init__(self):
        '''
        Constructor
        '''
        self.logical_memory = LogicalMemory()
    
    def setDriver(self, driver):
        self.driver = driver
    
    def readAndAnalyzeLogicalMemoryMap(self, tag_id, start_address, data_format):
        '''
        start_address -- a int data
        data_format -- Data Format
        '''        
        print "++++++++++++++++++++++++++++++++++++++++++++Read and Analyze++++++++++++++++++++++++++++++++++++++++++++"
        existing_data_set = list()
        
        index = start_address
        print data_format.DATA_FORMAT_ID
        print RootOIDEncoded.DATA_FORMAT_ID
        
        if data_format.DATA_FORMAT_ID == RootOIDEncoded.DATA_FORMAT_ID:
            ##########################################################################################
            #Extract Root OID
            #depend RootOID
            root_oid_data_set = DataSet()
            precursor = self.driver.readUserMemory(tag_id, index, 1)
            root_oid_data_set.PRECURSOR = Util.convertHexToBit(precursor)
            
            if DataFormatUtil.isOffset(precursor) == True:
                "has offset"
                pass
            
            index += 1            
            length_of_root_OIR = data_format.decodePrecursorRootOID(precursor)
            root_OID = self.driver.readUserMemory(tag_id, index, length_of_root_OIR["length_of_object_identifier"])
            root_oid_data_set.OBJECT_IDENTIFIER = root_OID
            index += int(precursor, 16)
            root_oid_data_set.LENGTH_OF_OBJECT = self.driver.readUserMemory(tag_id, index, 1)
            self.logical_memory.addDataSet(root_oid_data_set)
            existing_data_set.append(root_oid_data_set)
            index += 1 

        ##########################################################################################
        #Extract OID
        while True:
            print "PRECURSOR  address ",index
            precursor = self.driver.readUserMemory(tag_id, index, 1)            
            print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
            print "PRECURSOR IS ", precursor
            print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
            
            if precursor == "00" or precursor == "":
                break
            
            data_set = DataSet()
            data_set.PRECURSOR = Util.convertHexToBit(precursor)
            if DataFormatUtil.isOffset(precursor) == True:
                pass
            
            print "isPrecursorHaveAllObjectIdentifier is ", DataFormatUtil.isPrecursorHaveAllObjectIdentifier(precursor)
            
            if DataFormatUtil.isPrecursorHaveAllObjectIdentifier(precursor) == False:
                index += 1
                
                #check next data which decides length of object identifier or relative-oid. 
                length_of_object_identifier_type = self.driver.readUserMemory(tag_id, index, 1)
                
                if int(length_of_object_identifier_type, 16) <= (127 - 15):
                    #relative-oid
                    data_set.OBJECT_IDENTIFIER = length_of_object_identifier_type
                    index += 1
                                        
                else:
                    #length of object identifier
                    #defined D5
                    length_bit = Util.convertHexToBit(length_of_object_identifier_type)
                    
                    if length_bit[:3] == "100":
                        length_bit[3:]
                        data_set.LENGTH_OF_OBJECT_IDENTIFIER = length_of_object_identifier_type 
                        pass
                    elif length_bit[:3] == "101":
                        index += 1
                        length_of_object_identifier_type += self.driver.readUserMemory(tag_id, index, 1)
                        
                        data_set.LENGTH_OF_OBJECT_IDENTIFIER = length_of_object_identifier_type
                
                    length_of_object_identifier = DataFormatUtil.decodeLengthOfObjectIdentifierType(length_of_object_identifier_type)

                    index += 1
                
                    data_set.OBJECT_IDENTIFIER = self.driver.readUserMemory(tag_id, index, length_of_object_identifier)
                    index += length_of_object_identifier
                    
            else:
                index += 1
            
            length_of_object = self.driver.readUserMemory(tag_id, index, 1)

            while DataFormatUtil.isLengthOfObject(length_of_object) == False:
                index += 1
                length_of_object += self.driver.readUserMemory(tag_id, index, 1)

            data_set.LENGTH_OF_OBJECT = length_of_object
            decoded_length_object = DataFormatUtil.decodeLengthOfObject(length_of_object)
            index += 1
            data_set.OBJECT = self.driver.readUserMemory(tag_id, index, decoded_length_object)
            
            index += decoded_length_object
            self.logical_memory.addDataSet(data_set)
            existing_data_set.append(data_set)
            print data_set.showDataSet()
            print "--"
        return existing_data_set
        
    def addData(self, tag_id, dsfid_on_tag, data_format, add_objects_list):        
        '''
        dsfid -- a DSFID Object
        add_objects -- a List of OBJECTS
        '''
        print "NON-Directory"
        ########################################################################
        # Read Sequence
        # Sequential Read and Analyzer        
        existing_data_set_list = [] 
        if dsfid_on_tag != "":
            existing_data_set_list = self.readAndAnalyzeLogicalMemoryMap(tag_id, 0, data_format)
                
        ########################################################################
        # convert add_object_list to DataSet
        add_data_set_list = DataFormatUtil.convertDataSet(add_objects_list)

        ########################################################################
        #reference 15962 Annex G5
        #formatting
        
        formatted_add_data_set_list = data_format.formattingDataSet(existing_data_set_list, add_data_set_list)
        
        start_write_data = 0
        
        for index in range(len(formatted_add_data_set_list)):
            data_set = formatted_add_data_set_list[index]
            
            #this event will be throw Exception
            print data_set.showDataSet()
            print "Data is ", data_set.getLogicalMemory().upper()
            
            self.driver.writeUserMemory(tag_id, start_write_data, data_set.getLogicalMemory().upper(), False)
            #added data-set
            formatted_add_data_set_list[index].isAdded()
            start_write_data += len(data_set.getLogicalMemory()) / 2
        
        self.driver.writeUserMemory(tag_id, start_write_data, "00")
        
        
        
    def readData(self, tag_id, data_format, read_type):
        existing_data_set = []
                
        if read_type == ReadObjectsCRU.READ_ALL_OBJECTS:
            existing_data_set = self.readAndAnalyzeLogicalMemoryMap(tag_id, 0, data_format)            
        else:
            raise "UNIMPLEMENTED"

        add_object_list = data_format.decodeDataSetToAddData(existing_data_set)
        return add_object_list
        
            
    def modifyData(self):
        pass
    
    def deleteData(self):
        pass